package nancal.mp.nexus.utils

import nancal.mp.model.nexus.NexusAssetEntity
import nancal.mp.model.nexus.NexusEntity
import nancal.mp.nexus.enums.NexusAssetTypeEnum
import nancal.mp.nexus.enums.NexusWorkStageEnum
import nancal.mp.nexus.properties.NexusProperties
import nancal.mp.nexus.properties.NexusTargetConfigProperty
import nancal.mp.service.NexusService
import nbcp.base.comm.*
import nbcp.base.db.*
import nbcp.base.enums.*
import nbcp.base.extend.*
import nbcp.base.json.*
import nbcp.base.utils.*
import nbcp.myoql.db.*
import nbcp.myoql.db.comm.*
import nbcp.myoql.db.mongo.*
import nbcp.myoql.db.mongo.base.*
import nbcp.myoql.db.mongo.component.*
import nbcp.myoql.db.mongo.entity.*
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Component
import org.springframework.util.unit.DataSize
import org.springframework.util.unit.DataUnit
import java.io.*
import java.util.*

import nbcp.base.annotation.*
import nbcp.base.annotation.mvc.*

@MyLogLevel(LogLevelScopeEnum.WARN)
@Component
class NexusWork {
    companion object {
        private val logger = LoggerFactory.getLogger(this::class.java)
        private var metadataPath = ".metadata"

        /**
         * 不以 / 结束！
         */
        private val MAVEN_HOME = System.getenv("MAVEN_HOME").AsString().trimEnd('/')
    }

    @Autowired
    lateinit var properties: NexusProperties

    private fun workItemsFile(repository: String): String =
        FileUtil.resolvePath(properties.basePath, repository, metadataPath, "items.txt")

    private fun workProcessLogFile(repository: String): String =
        FileUtil.resolvePath(properties.basePath, repository, metadataPath, "process.txt")

    private fun getRrepositoryPath(repository: String, vararg sect: String): String =
        FileUtil.resolvePath(properties.basePath, repository, "data", *sect)

    private var total = 0;

    class WorkProcessLog(
        var type: nancal.mp.nexus.enums.NexusWorkStageEnum = nancal.mp.nexus.enums.NexusWorkStageEnum.none,
        var index: Int = -1,
        var total: Int = -1,
        var pagerToken: String = ""
    )

    fun readWorkProcessLogFile(repository: String): WorkProcessLog {
        return File(workProcessLogFile(repository))
            .apply {
                if (this.exists() == false) {
                    return WorkProcessLog()
                }
            }.readText(const.utf8)
            .FromJson<WorkProcessLog>()!!
    }


    fun clear() {
        var path = File(properties.basePath);
        if (path.exists()) {
            path.deleteRecursively()
        }
    }

    /**
     * 读取配置仓库的所有数据
     *
     * @param nexusProperties
     */
    fun start() {
        if (MAVEN_HOME.isEmpty()) {
            throw RuntimeException("找不到环境变量: MAVEN_HOME")
        }


        properties.from.mavens.split(",")
            .filter { it.HasValue }
            .forEachIndexed { index, repository ->

                start(repository, index, nancal.mp.nexus.enums.NexusAssetTypeEnum.maven2)
            }

        properties.from.npms.split(",")
            .filter { it.HasValue }
            .forEachIndexed { index, repository ->
                start(repository, index, nancal.mp.nexus.enums.NexusAssetTypeEnum.npm)
            }

        properties.from.mavenSnapshots.split(",")
            .filter { it.HasValue }
            .forEachIndexed { index, repository ->
                start(repository, index, nancal.mp.nexus.enums.NexusAssetTypeEnum.maven2, true)
            }
    }

    fun start(repository: String, repositoryIndex: Int, type: nancal.mp.nexus.enums.NexusAssetTypeEnum, snapshot: Boolean = false) {
        val folder = File(workProcessLogFile(repository))
        folder.parentFile.mkdirs()

        logger.Important("开始 ${repository}...")
        //从第一页开始读，无分页参数

        readMetadata(repository)


        this.total = 0
        File(workItemsFile(repository)).forEachLine {
            this.total++
        }


        filter_snapshots(repository, snapshot)


        var total2 = 0;
        File(workItemsFile(repository)).forEachLine {
            total2++
        }

        if (total2 != this.total) {
            this.total = total2;
        }

        startDownlod(repository)


        startUpload(repository, repositoryIndex, type, snapshot)

        logger.Important("完成 ${repository}! 总条目:${total}")
    }

    @Autowired
    lateinit var nexusService: NexusService;

    private fun readMetadata(repository: String) {
        //下载的配置
        val from = properties.from
        if (from.hostUrl.isEmpty() || from.username.isEmpty()) {
            return;
        }


        var process = readWorkProcessLogFile(repository);
        if (process.type.IsIn(nancal.mp.nexus.enums.NexusWorkStageEnum.none, nancal.mp.nexus.enums.NexusWorkStageEnum.meta) == false) {
            return;
        }

        logger.Important("开始读取 ${repository} 元数据")

        var index = -1;
        var prevContinuationToken = process.pagerToken;
        while (true) {
            index++;
//            prevContinuationToken = downloadMetadata(repository, downloadUrl, prevContinuationToken)

            var metadata = nexusService.getMetadata(
                from.hostUrl,
                repository,
                prevContinuationToken,
                properties.from.username,
                properties.from.password
            );
            if (metadata.msg.HasValue) {
                throw RuntimeException(metadata.msg);
            }

            prevContinuationToken = metadata.data?.continuationToken.AsString();

            if (prevContinuationToken.isNullOrEmpty()) {
                writeWorkProcessLog(repository, nancal.mp.nexus.enums.NexusWorkStageEnum.tidy);
                break
            } else {
                writeWorkProcessLog(
                    repository,
                    nancal.mp.nexus.enums.NexusWorkStageEnum.meta,
                    -1,
                    metadata.data?.continuationToken.AsString()
                )
            }

            if (index > 0 && index % 50 == 0) {
                logger.Important("正在读取 ${repository} 元数据...,当前:${prevContinuationToken}")
            }
        }


        logger.Important("读取 ${repository} 元数据完成, 共:${index + 1} 页")
    }


    private fun getVersionOfSnapshot(item: NexusAssetEntity): String {
        return item.path
            .Slice((item.maven2.groupId + item.maven2.artifactId).length + 1)
            .split("/")
            .filter { it.HasValue }
            .first()
    }

    private fun getVersionOfSnapshot(item: NexusEntity): String {
        /*
    {"id":"bWF2ZW4tc25hcHNob3RzOjM2ZTNkZWM4ZGU1MjhjOWI3NTMxNjMzZWYyNGU2ZDE2","repository":"maven-snapshots",

    "format":"maven2",
    "group":"com.nancal",
    "name":"nancal-framework",
    "version":"1.0.0-20210420.061218-1",

    "assets":[
    {"id":"bWF2ZW4tc25hcHNob3RzOjE4ZGRlY2NkZmI0OTFlY2I3ZTFjZmE3ZTE5NGYxMjdh",
    "downloadUrl":"http://nexus.cloudnk.cn/repository/maven-snapshots/com/nancal/nancal-framework/1.0.0-SNAPSHOT/nancal-framework-1.0.0-20210420.061218-1.pom",
    "path":"com/nancal/nancal-framework/1.0.0-SNAPSHOT/nancal-framework-1.0.0-20210420.061218-1.pom",
    "repository":"maven-snapshots",
    "format":"maven2",
    "contentType":"application/xml",
    "maven2":{"extension":"pom","groupId":"com.nancal","artifactId":"nancal-framework","version":"1.0.0-20210420.061218-1"}
    },

    {"id":"bWF2ZW4tc25hcHNob3RzOjE4ZGRlY2NkZmI0OTFlY2IxOTdlNjc0Y2UwYmE4NDk5","downloadUrl":"http://nexus.cloudnk.cn/repository/maven-snapshots/com/nancal/nancal-framework/1.0.0-SNAPSHOT/nancal-framework-1.0.0-20210420.061218-1.pom.md5","path":"com/nancal/nancal-framework/1.0.0-SNAPSHOT/nancal-framework-1.0.0-20210420.061218-1.pom.md5","repository":"maven-snapshots","format":"maven2","contentType":"text/plain","maven2":{"extension":"pom.md5","groupId":"com.nancal","artifactId":"nancal-framework","version":"1.0.0-20210420.061218-1"}},{"id":"bWF2ZW4tc25hcHNob3RzOjE4ZGRlY2NkZmI0OTFlY2I4NTgzYjhlYWU4ZDA2NmJj","downloadUrl":"http://nexus.cloudnk.cn/repository/maven-snapshots/com/nancal/nancal-framework/1.0.0-SNAPSHOT/nancal-framework-1.0.0-20210420.061218-1.pom.sha1","path":"com/nancal/nancal-framework/1.0.0-SNAPSHOT/nancal-framework-1.0.0-20210420.061218-1.pom.sha1","repository":"maven-snapshots","format":"maven2","contentType":"text/plain","maven2":{"extension":"pom.sha1","groupId":"com.nancal","artifactId":"nancal-framework","version":"1.0.0-20210420.061218-1"}}]}
         */
        //找出中间的版本.
        return item.assets.first().path.Slice((item.group + item.name).length + 1).split("/").filter { it.HasValue }
            .first()
    }


    private fun filter_snapshots(repository: String, snapshot: Boolean) {
        var process = readWorkProcessLogFile(repository);
        if (process.type != nancal.mp.nexus.enums.NexusWorkStageEnum.tidy) {
            return;
        }

        //对 items.txt 去重.
        if (snapshot == false) {
            writeWorkProcessLog(repository, nancal.mp.nexus.enums.NexusWorkStageEnum.down)
            return;
        }

        var fileRecord = File(FileUtil.resolvePath(properties.basePath, repository, metadataPath, ".record.txt"))

        if (process.index < 0) {
            File(workItemsFile(repository) + ".sn").delete();
            fileRecord.delete()
        }

        logger.Important("正在整理元数据,共: ${total}")

        var records: MutableSet<String> = mutableSetOf<String>();

        if (fileRecord.exists()) {
            records = fileRecord.readLines(const.utf8).filter { it.isNotEmpty() }.toMutableSet()
        }


        //循环每一项,和下一项比较! 大的-> i-{group}-{name}-{version}.txt
        var start = process.index;
        var index = -1;
        var file = File(workItemsFile(repository))


        //如果小于 60Mb
        if (DataSize.ofBytes(file.length()).toMegabytes() > 60) {
            tidy_snapshot_meta_use_file(repository, file, start, records, fileRecord);
        } else {
            var list = file.readLines(const.utf8)
                .filter { it.HasValue }
                .map {
                    it.FromJson<NexusEntity>()!!
                }

            tidy_snapshot_meta_use_mem(repository, list, start, records, fileRecord)
        }



        File(workItemsFile(repository) + ".bak").delete();
        File(workItemsFile(repository)).renameTo(File(workItemsFile(repository) + ".bak"))
        File(workItemsFile(repository) + ".sn").renameTo(File(workItemsFile(repository)))


        writeWorkProcessLog(repository, nancal.mp.nexus.enums.NexusWorkStageEnum.down)
    }

    private fun tidy_snapshot_meta_use_mem(
        repository: String,
        list: List<NexusEntity>,
        start: Int,
        records: MutableSet<String>,
        fileRecord: File
    ) {
        var index = -1;
        var step = getStepOf100(total);

        list
            .forEach { current ->
                index++;

                if (index <= start) {
                    return@forEach
                }

                if (index > 0 && index % step == 0) {
                    logger.Important("tidy: ${index}/${total} = ${index * 100 / total}% , 去重后条目: ${records.size}")
                }

                var key = current.group + "/" + current.name + "/" + getVersionOfSnapshot(current)
                if (records.contains(key)) {
                    return@forEach
                }

                var max = getMaxSnapshotVersionLineFromMem(repository, list, current, index)
                appendItemLatestVersion(repository, max);

                records.add(key);
                fileRecord.appendText(key + "\n")

                writeWorkProcessLog(repository, nancal.mp.nexus.enums.NexusWorkStageEnum.tidy, index)
            }
    }

    private fun tidy_snapshot_meta_use_file(
        repository: String,
        file: File,
        start: Int,
        records: MutableSet<String>,
        fileRecord: File
    ) {
        var index = -1;
        var step = getStepOf100(total);

        file
            .forEachLine { line ->
                index++;

                if (index <= start) {
                    return@forEachLine
                }

                if (index > 0 && index % step == 0) {
                    logger.Important("tidy: ${index}/${total} = ${index * 100 / total}% , 去重后条目: ${records.size}")
                }

                if (line.isEmpty()) {
                    return@forEachLine
                }

                var current = line.FromJson<NexusEntity>()!!

                var key = current.group + "/" + current.name + "/" + getVersionOfSnapshot(current)
                if (records.contains(key)) {
                    return@forEachLine
                }

                var max = getMaxSnapshotVersionLineFromFile(repository, current, index)
                appendItemLatestVersion(repository, max);

                records.add(key);
                fileRecord.appendText(key + "\n")

                writeWorkProcessLog(repository, nancal.mp.nexus.enums.NexusWorkStageEnum.tidy, index)
            }

    }

    private fun getStepOf100(total: Int): Int {
        var step = Math.floor(total / 20.0).toInt();
        if (step < 10) {
            step = 10;
        }
        return step;
    }

    private fun getMaxSnapshotVersionLineFromFile(repository: String, find: NexusEntity, start: Int): NexusEntity {
//        var versionPrefix = getVersionOfSnapshot( find).replace("SNAPSHOT","");

        var max: NexusEntity? = null;
        var index = start;
        File(workItemsFile(repository))
            .forEachLine { line ->
                index++;

                if (line.isEmpty()) {
                    return@forEachLine
                }

                if (line.contains("\"" + find.group + "\"") == false) {
                    return@forEachLine
                }

                if (line.contains("\"" + find.name + "\"") == false) {
                    return@forEachLine
                }

                var current = line.FromJson<NexusEntity>()!!


                if (find.group != current.group ||
                    find.name != current.name ||
                    getVersionOfSnapshot(find) != getVersionOfSnapshot(current)
                ) {
                    return@forEachLine
                }

                if (seqVersion(find, current)) {
                    max = current;
                }
            }

        return max ?: find
    }


    private fun getMaxSnapshotVersionLineFromMem(
        repository: String,
        list: List<NexusEntity>,
        find: NexusEntity,
        start: Int
    ): NexusEntity {
//        var versionPrefix = getVersionOfSnapshot( find).replace("SNAPSHOT","");

        var max: NexusEntity? = null;
        var index = start;
        list
            .forEach { current ->
                index++;

                if (find.group != current.group ||
                    find.name != current.name ||
                    getVersionOfSnapshot(find) != getVersionOfSnapshot(current)
                ) {
                    return@forEach
                }

                if (seqVersion(find, current)) {
                    max = current;
                }
            }

        return max ?: find
    }

    private fun seqVersion(prev: NexusEntity, current: NexusEntity): Boolean {
        return listOf(prev.version, current.version).sorted().first() == prev.version
    }

    private fun appendItemLatestVersion(repository: String, prev: NexusEntity) {
//        var version = getVersionOfSnapshot(prev);
//        prev.version = version
//
//        prev.assets.forEach {
//            it.path = getPathOfSnapshotPath(it)
//            it.maven2.version = version
//        }
        File(workItemsFile(repository) + ".sn").appendText(prev.ToJson() + const.line_break)
    }

    private fun getPathOfSnapshotPath(asset: NexusAssetEntity): String {
        var version = getVersionOfSnapshot(asset);

        var sects = asset.path.split("/").toMutableList()
        sects[sects.size - 1] = sects[sects.size - 1].replace(asset.maven2.version, version);
        return sects.joinToString("/")
//        var list = mutableListOf<String>();
//        list.addAll(asset.maven2.groupId.split("."))
//        list.add(asset.maven2.artifactId)
//        list.add(version);
//        list.add(asset.maven2.artifactId + "-" + version + "." + asset.maven2.extension)
//
//        return list.joinToString("/")
    }


//    private fun filter_snapshots(items: MutableList<NexusEntity>) {
//        if (properties.snapshot.enable == false) return;
//
//        var set = items.groupBy { it.group + "/" + it.name + "/" + getVersionOfSnapshot(it) }
//            .mapValues { it.value.map { it.version }.sortedDescending().first() }
//
//        if (set.size == items.size) {
//            return;
//        }
//
//        items.removeAll {
//            var maxItemVersion = set.get(it.group + "/" + it.name + "/" + getVersionOfSnapshot(it));
//
//            return@removeAll it.version != maxItemVersion
//        }
//    }


    private fun writeWorkProcessLog(
        repository: String,
        errorType: nancal.mp.nexus.enums.NexusWorkStageEnum,
        index: Int = -1,
        pagerToken: String = ""
    ) {
        File(workProcessLogFile(repository))
            .writeText(
                WorkProcessLog(errorType, index, total, pagerToken).ToJson(),
                const.utf8
            )
    }

    /**
     * 下载
     *
     * @param start
     */
    private fun startDownlod(repository: String) {
        val from = properties.from
        if (from.hostUrl.isEmpty() || from.username.isEmpty()) {
            return;
        }


        var process = readWorkProcessLogFile(repository);
        if (process.type != nancal.mp.nexus.enums.NexusWorkStageEnum.down) {
            return;
        }

        logger.Important("开始下载${repository},共:${total}")

        var start = process.index;
        var step = getStepOf100(total);

        var index = -1;
        File(workItemsFile(repository))
            .forEachLine { line ->
                index++;

                if (index <= start) {
                    return@forEachLine
                }

                if (index > 0 && index % step == 0) {
                    logger.Important("下载${repository}: ${index}/${total} = ${index * 100 / total}%")
                }

                val nexusEntity = line.FromJson<NexusEntity>()!!

                doDownlod(repository, nexusEntity);
                writeWorkProcessLog(repository, nancal.mp.nexus.enums.NexusWorkStageEnum.down, index)
            }

        logger.Important("完成下载${repository},共:${total}")

        writeWorkProcessLog(repository, nancal.mp.nexus.enums.NexusWorkStageEnum.upload)
    }

    @Throws(IOException::class)
    fun doDownlod(repository: String, nexusEntity: NexusEntity) {
        nexusEntity.assets.forEach { assetEntity ->
            var target = File(getRrepositoryPath(repository, assetEntity.path));
            target.parentFile.mkdirs();

            val ajax = HttpInvoke()(assetEntity.downloadUrl)
            ajax.withMaxTryTimes(3)
            ajax.doDownloadFile(target.FullName)
        }

        //验证 Md5
        nexusEntity.assets.forEach { assetEntity ->
            var target = File(getRrepositoryPath(repository, assetEntity.path));

            if (target.endsWith(".md5")) {
                if (target.readLines(const.utf8).first() != Md5Util.getFileMD5(File(target.FullName.Slice(0, -4)))) {
                    throw RuntimeException("md5校验不通过！")
                }
            }
        }
    }

    /**
     * 上传私服 mavne2
     *
     * @return
     */
    fun startUpload(
        repository: String,
        repositoryIndex: Int,
        nexusAssetTypeEnum: nancal.mp.nexus.enums.NexusAssetTypeEnum,
        snapshot: Boolean = false
    ) {

        properties.targets.forEach { target ->
            startUploadTarget(
                repository,
                repositoryIndex,
                nexusAssetTypeEnum,
                target,
                snapshot
            )
        }

    }

    fun startUploadTarget(
        repository: String,
        repositoryIndex: Int,
        nexusAssetTypeEnum: nancal.mp.nexus.enums.NexusAssetTypeEnum,
        target: NexusTargetConfigProperty,
        snapshot: Boolean = false
    ) {
        if (target.hostUrl.isEmpty() || target.username.isEmpty()) {
            return;
        }

        var process = readWorkProcessLogFile(repository);
        if (process.type != nancal.mp.nexus.enums.NexusWorkStageEnum.upload) {
            return;
        }

        var targetRepository = "";
        if (nexusAssetTypeEnum == nancal.mp.nexus.enums.NexusAssetTypeEnum.maven2) {
            if (snapshot) {
                targetRepository = target.mavenSnapshots.split(",").elementAtOrElse(repositoryIndex, { "" })
            } else {
                targetRepository = target.mavens.split(",").elementAtOrElse(repositoryIndex, { "" })
            }
        } else if (nexusAssetTypeEnum == nancal.mp.nexus.enums.NexusAssetTypeEnum.npm) {
            targetRepository = target.npms.split(",").elementAtOrElse(repositoryIndex, { "" })
        }


        if (targetRepository.isEmpty()) {
            return;
        }

        //只能从头开始上传.
        var start = -1

        logger.Important("开始上传 ${repository} --> ${target.hostUrl} (${targetRepository}) ,共${total}")

        var step = getStepOf100(total)
        var index = -1;
        File(workItemsFile(repository))
            .forEachLine { line ->
                index++;
                if (index <= start) {
                    return@forEachLine
                }

                if (index > 0 && index % step == 0) {
                    logger.Important("上传${target.hostUrl}.${targetRepository}: ${index}/${total} = ${index * 100 / total}%")
                }

                val nexusEntity = line.FromJson<NexusEntity>()!!

                if (nexusEntity.format == nancal.mp.nexus.enums.NexusAssetTypeEnum.maven2.toString()) {
                    //如果有大于50Mb的包,报警
                    var jar = nexusEntity.assets.firstOrNull {
                        it.path.endsWith(".jar") && !it.path.endsWith("-javadoc.jar") && !it.path.endsWith("-sources.jar")
                    }

                    if (jar != null) {
                        var jarPath = FileUtil.resolvePath(
                            properties.basePath,
                            repository,
                            "data",
                            jar.path
                        )

                        if (File(jarPath).length() > DataSize.of(50, DataUnit.MEGABYTES).toBytes()
                        ) {
                            logger.Important("${jarPath} 文件大于50Mb,跳过!")
                            return@forEachLine
                        }
                    }

                    if (snapshot) {
                        uploadSnapshotUseMvnShell(nexusEntity, repository, target, targetRepository);
                    } else {
                        uploadMaven(nexusEntity, repository, snapshot, target, targetRepository)
                    }
                } else if (nexusEntity.format == nancal.mp.nexus.enums.NexusAssetTypeEnum.npm.toString()) {
                    uploadNpm(nexusEntity, repository, target, targetRepository)
                }

                writeWorkProcessLog(repository, nancal.mp.nexus.enums.NexusWorkStageEnum.upload, index)
            }


        logger.Important("上传完成 ${repository} --> ${target.hostUrl}.${targetRepository} ,共${total}")
    }

    fun uploadMaven(
        entity: NexusEntity,
        repository: String,
        snapshot: Boolean,
        target: NexusTargetConfigProperty,
        targetRepository: String
    ) {
        if (entity.format != nancal.mp.nexus.enums.NexusAssetTypeEnum.maven2.toString()) {
            throw RuntimeException("不是maven")
        }

        if (snapshot) {
            throw RuntimeException("不能是 snapshot")
            return;
        }

        //用HttpEntity封装整个请求报文
        var ajax = HttpInvoke()(
            UrlUtil.joinUrl(
                target.hostUrl,
                "/service/rest/v1/components?repository=" + targetRepository
            )
        )

        ajax.withMaxTryTimes(3)
        ajax.request.connectTimeout = 3000
        ajax.request.setAuthorization(target.username, target.password)


        var jars = getMavenPostForm(entity, repository);
        if (jars.any()) {
            var ret = ajax.submitForm(jars);
            if (ajax.isError) {
                throw RuntimeException(ajax.status.toString() + ":" + ret)
            }
        }
    }

    private fun uploadSnapshotUseMvnShell(
        entity: NexusEntity,
        repository: String,
        target: NexusTargetConfigProperty,
        targetRepository: String
    ) {

        //准备mvn
//        writeMvnSettingConf(target);


        var shell = mutableListOf<String>()
//        if (System.getProperty("os.name").contains("window", true)) {
//            shell += "cmd"
//            shell += "/c"
//        } else {
//            shell += "bash";
//            shell += "-c"
//        }


        shell += FileUtil.resolvePath(MAVEN_HOME, "bin", "mvn");

//        if (target.snapshot.settingFile.HasValue) {
//            deploy += """ -s ${target.snapshot.settingFile} """
//        }

        shell += """ deploy:deploy-file  """
        shell += """ -DgroupId=${entity.group} """
        shell += """ -DartifactId=${entity.name} """
        shell += """ -Dversion=${getVersionOfSnapshot(entity)} """
        shell += """ -Durl=${
            WebUtil.fillUrlWithUserPassword(
                target.hostUrl,
                target.username,
                target.password
            )
        }/repository/${targetRepository} """

//  -DrepositoryId=${target.snapshot.serverId}
        var pom = entity.assets.firstOrNull { it.path.endsWith(".pom") }
        var jar = entity.assets.firstOrNull {
            it.path.endsWith(".jar") && !it.path.endsWith("-javadoc.jar") && !it.path.endsWith("-sources.jar")
        }
        var jardoc = entity.assets.firstOrNull { it.path.endsWith("-javadoc.jar") }
        var sources = entity.assets.firstOrNull { it.path.endsWith("-sources.jar") }


        if (jar != null) {
            shell += "  -Dfile=${FileUtil.resolvePath(properties.basePath, repository, "data", jar.path)} "

            if (pom != null) {
                shell += "  -DpomFile=${FileUtil.resolvePath(properties.basePath, repository, "data", pom.path)} "
            }
        } else {
            if (pom != null) {
                shell += "  -Dpackaging=pom  -Dfile=${
                    FileUtil.resolvePath(
                        properties.basePath,
                        repository,
                        "data",
                        pom.path
                    )
                } "
            }
        }

        if (jardoc != null) {
            shell += "  -Djavadoc=${FileUtil.resolvePath(properties.basePath, repository, "data", jardoc.path)} "
        }

        if (sources != null) {
            shell += "  -Dsources=${FileUtil.resolvePath(properties.basePath, repository, "data", sources.path)} "
        }
        
        ShellUtil.execRuntimeCommand(shell)
            .apply {
                if (this.msg.HasValue) {
                    throw RuntimeException(this.msg);
                }
            }
    }

//    private fun writeMvnSettingConf(target: NexusTargetConfigProperty) {

//    if (File(FileUtil.resolvePath(target.snapshot.mvnPath, "conf", "settings.conf.bak")).exists() == false) {
//        File(
//            FileUtil.resolvePath(
//                target.snapshot.mvnPath,
//                "conf",
//                "settings.conf"
//            )
//        ).renameTo(File(FileUtil.resolvePath(target.snapshot.mvnPath, "conf", "settings.conf.bak")))
//    }


//        ClassPathResource("maven-settings.xml").inputStream.readContentString()
//            .formatWithJson(
//                JsonMap(
//                    "serverId" to target.snapshot.serverId,
//                    "username" to target.username,
//                    "password" to target.password
//                ),
//                style = "@@"
//            )
//            .apply {
//                File(FileUtil.resolvePath(target.snapshot.mvnPath, "conf", "settings.conf"))
//                    .writeText(this, const.utf8)
//            }
//    }

    private fun getMavenPostForm(entity: NexusEntity, repository: String): Map<String, Any> {
        val form = mutableMapOf<String, Any>()

        var index = 1;


        form.put("maven2.groupId", entity.group)
        form.put("maven2.artifactId", entity.name)
        form.put("maven2.version", entity.version)
        form.put("maven2.generate-pom", "false")

        var asset = entity.assets.firstOrNull { it.maven2.extension == "pom" }
        //仅有pom
        if (asset != null) {
            form.put("maven2.asset${index}", File(getRrepositoryPath(repository, asset.path)))
            form.put("maven2.asset${index}.extension", asset.maven2.extension)
            index++;
        }


        asset = entity.assets.firstOrNull {
            it.maven2.extension == "jar" && !it.path.endsWith("-javadoc.jar") && !it.path.endsWith("-sources.jar")
        }
        if (asset != null) {
            form.put("maven2.asset${index}", File(getRrepositoryPath(repository, asset!!.path)))
            form.put("maven2.asset${index}.extension", asset!!.maven2.extension)
            index++
        }

        asset = entity.assets.firstOrNull { it.path.endsWith("-sources.jar") }
        if (asset != null) {
            form.put("maven2.asset${index}", File(getRrepositoryPath(repository, asset!!.path)))
            form.put("maven2.asset${index}.extension", asset!!.maven2.extension)
            form.put("maven2.asset${index}.classifier", "sources")
            index++;
        }

        asset = entity.assets.firstOrNull { it.path.endsWith("-javadoc.jar") }
        if (asset != null) {
            form.put("maven2.asset${index}", File(getRrepositoryPath(repository, asset!!.path)))
            form.put("maven2.asset${index}.extension", asset!!.maven2.extension)
            form.put("maven2.asset${index}.classifier", "javadoc")
            index++;
        }

        return form;
    }


    /**
     * 上传私服 npm
     *
     * @param file      文件
     * @param npm       属性
     * @param uploadUrl 上传地址
     * @return
     */
    fun uploadNpm(
        entity: NexusEntity,
        repository: String,
        target: NexusTargetConfigProperty,
        targetRepository: String
    ) {
        if (entity.format != nancal.mp.nexus.enums.NexusAssetTypeEnum.npm.toString()) {
            throw RuntimeException("不是npm")
        }

        entity.assets.forEach { asset ->
            val form = mutableMapOf<String, Any>()
            form.put("npm.asset", File(getRrepositoryPath(repository, asset.path)))
            //用HttpEntity封装整个请求报文
            var ajax = HttpInvoke()(
                UrlUtil.joinUrl(
                    target.hostUrl,
                    "/service/rest/v1/components?repository=" + targetRepository
                )
            )

            ajax.withMaxTryTimes(3)
            ajax.request.connectTimeout = 3000
            ajax.request.setAuthorization(target.username, target.password)

            ajax.submitForm(form)

            if (ajax.isError) {
                throw RuntimeException("上传失败")
            }
        }
    }
}